package com.fs.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.fs.common.constant.CacheConstants;
import com.fs.common.constant.UserConstants;
import com.fs.common.core.pojo.SysUser;
import com.fs.common.core.vo.LoginUser;
import com.fs.common.enums.UserStatus;
import com.fs.common.exception.ServiceException;
import com.fs.common.exception.user.*;
import com.fs.common.util.DateUtils;
import com.fs.common.util.RedisCache;
import com.fs.common.util.ip.IpUtils;
import com.fs.system.service.ISysConfigService;
import com.fs.system.service.ISysLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

@Service
public class SysLoginServiceImpl implements ISysLoginService {
    @Autowired
    ISysConfigService configService;
    @Autowired
    RedisCache redisCache;
    @Autowired
    SysUserServiceImpl userService;
    @Autowired
    SysPasswordService passwordService;
    @Autowired
    TokenService tokenService;
    @Autowired
    AuthenticationManager authenticationManager;

    @Override
    public String login(String username, String password, String code, String uuid) {
        //先检验验证码
        validateCaptcha(code,uuid);
        //开始用户名和密码的前置检验
        loginPreCheck(username,password);
        Authentication authentication = null;
        try{
            //创建一个Authentication认证对象,  属性: authenticated =false, 没有被认证
            UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

            //返回一个认证对象:  被认证认证对象
            authentication = authenticationManager.authenticate(authRequest);
        }catch (Exception e){
            throw new  ServiceException("用户不存在/密码错误");
        }
        //获取认证通过的UserDetails对象
        LoginUser loginUser = (LoginUser)authentication.getPrincipal();

        //调用tokenService的createToken()创建token
        String token = tokenService.createToken(loginUser);

        //6.修改SysUser表的登录ip,登录时间
        recordLoginInfo(loginUser.getUserId());
        //return token;
        return token;

    }

    @Override
    public void validateCaptcha( String code, String uuid) {
          //该方法用于检测验证码，
        //先检测系统是否有开启验证码功能
       boolean isCaptchaEnabled= configService.selectCaptchaEnabled();
       if(isCaptchaEnabled){
           String key= CacheConstants.CAPTCHA_CODE_KEY+uuid;//获取到正确验证码的key
           String captcha=redisCache.getCacheObject(key);//获取到正确的验证码
           redisCache.deleteObject(key);//当这个验证码验证完毕后，在redis中就不需要再存储，
           if(captcha==null){
               throw new CaptchaExpireException();//如果redis中获取到的验证码为空，证明该验证码已经失效，因此要报一个自定义的验证码失效异常
           }
           if(!captcha.equals(code)){
               throw new CaptchaException();//输入的验证码匹配不上，证明输入验证码错误
           }
       }
    }

    @Override
    public void recordLoginInfo(Long userId) {
         //修改user表中的登录时间和登录IP等字段
        SysUser user=new SysUser();
        user.setUserId(userId);
        user.setLoginDate(DateUtils.getNowDate());
        user.setLoginIp(IpUtils.getIpAddr());
        userService.updateUser(user);
    }

    //该方法为用户名和密码的前置校验，目的是筛选出长度不符合规定，或者为空的用户名/密码。
    public void loginPreCheck(String username, String password){


        //检测用户名/密码是否为空
        if(StrUtil.isEmpty(username)||StrUtil.isEmpty(password)){
            throw new UserNotExistsException();
        }
        //检测用户名的长度
        if(username.length()> UserConstants.USERNAME_MAX_LENGTH || username.length()<UserConstants.USERNAME_MIN_LENGTH){
            throw new UserPasswordNotMatchException();
        }
        //检测密码的长度
        if(password.length()> UserConstants.PASSWORD_MAX_LENGTH || password.length()<UserConstants.PASSWORD_MIN_LENGTH){
            throw new UserPasswordNotMatchException();
        }
        //校验黑名单

        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
        {
            throw new BlackListException();
        }
    }

}
